package srzy.socket

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.TIMEOUT
import java.net.SocketTimeoutException
import srzy.common.Logging
import srzy.common.Config
import srzy.diameter._
import srzy.rb._
import srzy.common.Common

class RBServerReceActor(rbServerMsgActor: RBServerMsgActor) extends Actor with Logging {

  override def act = {
    logger.debug("RBServerReceActor start")
    while (true) {
      try {
        val msg = rbServerMsgActor.socketConn.read
        getMsgType(msg) match {
          case i: Int => {
            logger.debug("service msg rece [" + i + "]")
            rbServerMsgActor ! ('rece, msg)
          }
        }
      } catch {
        case ste: SocketTimeoutException =>
      }
    }
  }

  override def exceptionHandler = {
    case ioe: java.io.IOException => {
      logger.error(ioe.getMessage(), ioe)
      sys.exit
    }
    case e: Exception => logger.error(e.getMessage(), e)
  }

}

class RBServerMsgActor(getRBSocket: => java.net.Socket) extends Actor with Logging {

  def getNewRBSocketConn = new RBSocketConn {
    val socket = getRBSocket
    val outStream = socket.getOutputStream()
    val inStream = socket.getInputStream()
  }

  var socketConn: RBSocketConn = getNewRBSocketConn

  var oc: scala.actors.OutputChannel[Any] = null
  var rbServerReceActor: RBServerReceActor = null

  def authentication = {
    logger.debug("authentication start")
    var flag = true
    while (flag == true) {
      try {
        var msg = socketConn.read()
        logger.debug("rece authentication msg:" + msg)
        socketConn.write(RBSocketConn.ECAMsg)
        logger.debug("send authentication msg:" + RBSocketConn.ECAMsg)
        socketConn.sendHeartbeat
        logger.debug("send Heartbeat msg")

        msg = socketConn.read()
        logger.debug("rece Heartbeat msg:" + msg)
        if (getMsgType(msg) != CODE_KAA && Integer.parseInt(getErrorCode(msg)) != 0) {
          logger.debug("MsgType : " + getMsgType(msg) + ",ErrorCode : " + getErrorCode(msg))
          throw new Exception("Heartbeat msg error")
        }
        flag = false
      } catch {
        case ex: Exception =>
          logger.debug("socketConn write error", ex)
          socketConn.close()
          socketConn = getNewRBSocketConn
      }
    }
    logger.debug("authentication over")
  }

  val clq = new java.util.concurrent.LinkedBlockingQueue[String](500)

  override def act = {
    loop {
      reactWithin(6000) {
        case sendMsg: String => {
          logger.debug("send to sm : " + sendMsg)
          socketConn.write(sendMsg)
          logger.debug("send over ")
          sender ! 'ok
        }
        case 'getRece => {
          if (clq.peek() == null) {
            oc = sender
            //            receRequestTime = System.currentTimeMillis()
          } else {
            sender ! clq.poll()
          }
        }
        case ('rece, receMsg: String) => {
          if (oc != null) {
            oc ! receMsg
            oc = null
          } else {
            clq.offer(receMsg)
          }
        }
        case 'exit => {
          //          (rbServerReceActor !! 'exit).apply
          socketConn.close
          sender ! 'ok
          exit()
        }
        case TIMEOUT => {
          if (oc != null) {
            oc ! ""
            oc = null
          }
        }
        case a: Any =>
          logger.error("unknown pattern " + a.toString)
      }
    }
  }

  override def start(): Actor = synchronized {
    super.start()
    rbServerReceActor = new RBServerReceActor(RBServerMsgActor.this)
    authentication
    rbServerReceActor.start
    RBServerMsgActor.this
  }

  override def exceptionHandler = {
    case ioe: java.io.IOException => {
      logger.error(ioe.getMessage(), ioe)
      sys.exit
    }
    case e: Exception => logger.error(e.getMessage(), e)
  }

}

object RBServerMsgActor extends Logging {

  val port = Integer.parseInt(Config.getValue("root", "config", "RB_Server_Port"))
  //  val authenticationReceMsg = "[100=02][101=20150407094419069][210=172.168.1.248][003=0000]"

  val dccssc = new RBSocketServerConn {
    val serverSocket = SocketServerConn.create(port)
  }

  //  val socket = (a1 !! 'get).apply.asInstanceOf[java.net.Socket]
  //  val outStream = socket.getOutputStream()
  //  val inStream = socket.getInputStream()

  def getRBSocket = try {
    dccssc.accept
  } catch {
    case ex: Exception =>
      logger.error("create RBSocket error ", ex)
      exit()
  }

  val actor = new RBServerMsgActor(getRBSocket)
  //  actor.start

  def apply() = actor

}